<?php

namespace App\Package\Attendance;

use App\Models\Attendance;
use Illuminate\Support\Collection;

/**
 * 考勤原始数据校验逻辑
 *
 * Date: 30/04/2018
 * @author George
 * @package App\Package\Attendance
 */
class Examine
{
	const PI = 3.1415926;
	/**
	 * 临时存储
	 *
	 * Date: 30/04/2018
	 * @author George
	 */
	protected $attendances;

	/**
	 * Examine constructor.
	 * @param Collection $attendances
	 */
	public function __construct(Collection $attendances)
	{
		$this->attendances = $attendances;
	}

	public function result()
	{
		$this->attendances->map(function ($attendance) {
			$this->time($attendance);
		});
	}

	/**
	 * 计算考勤时间
	 *
	 * Date: 30/04/2018
	 * @author George
	 * @param Attendance $attendance
	 * @return Attendance
	 * @throws \Throwable
	 */
	public static function time(Attendance $attendance)
	{
		$delayed = config('attendance.delayed') * 60;
		$start = strtotime($attendance->schedule->start_timestamp);
		$end = strtotime($attendance->schedule->end_timestamp);

		if (! $attendance->checkin_time) {
			$attendance->checkin_status = config('attendance.status.nsignin');
		} else {
			$checkin = strtotime($attendance->checkin_time);
			// 当签到时间减去允许迟到时间大于考勤开始时间，则记为迟到
			if ($start < ($checkin - $delayed)) {
				$attendance->checkin_status = config('attendance.status.tardy');
			}
		}

		if ($attendance->checkout_time) {
			$checkout = strtotime($attendance->checkout_time);
			// 当签退时间小于考勤结束时间是，则记为早退
			if ($end > $checkout) {
				$attendance->checkout_status = config('attendance.status.early');
			}
		}

		$attendance->checkin_status = $attendance->checkin_status ?? config('attendance.status.normal');
		$attendance->checkout_status = $attendance->checkout_status ?? config('attendance.status.normal');
		$attendance->saveOrFail();
		return $attendance;
	}

	/**
	 * 判断考勤范围是否在范围内
	 *
	 * Date: 30/04/2018
	 * @author George
	 * @deprecated
	 * @param Attendance $attendance
	 * @return \Illuminate\Config\Repository|mixed
	 */
	protected function scope(Attendance $attendance)
	{
		$project = $attendance->project;
		$range = $this->calculationRange($project->longitude, $project->latitude, $project->radius);
		// 判断签到经度是否在范围内
		if ($attendance->checkin_longitude > $range['longitude']['start'] && $attendance->checkin_longitude < $range['longitude']['end']) {
			// 判断签到纬度是否在范围内
			if ($attendance->checkin_latitude > $range['latitude']['start'] && $attendance->checkin_latitude < $range['latitude']['end']) {
				// 判断签退经度是否在范围内
				if ($attendance->checkout_longitude > $range['longitude']['start'] && $attendance->checkout_longitude < $range['longitude']['end']) {
					// 判断签退纬度是否在范围内
					if ($attendance->checkout_latitude > $range['latitude']['start'] && $attendance->checkout_latitude < $range['latitude']['end']) {
						return config('attendance.status.normal');
					}
				}
			}
		}

		return config('attendance.status.beyond');
	}

	/**
	 * 给定坐标点和半径计算范围
	 *
	 * Date: 06/05/2018
	 * @author George
	 * @param $longitude
	 * @param $latitude
	 * @param float $distance
	 * @param int $radius
	 * @return array
	 */
	private function calculationRange($longitude, $latitude, $distance = 0.5, $radius = 6367000)
	{
		$dlongitude = 2 * asin(sin($distance / (2 * $radius)) / cos(deg2rad($latitude)));
		$dlongitude = rad2deg($dlongitude);
		$dlatitude = $distance / $radius;
		$dlatitude = rad2deg($dlatitude);

		return [
			'longitude' => [
				'start' => $longitude - $dlongitude,
				'end' => $longitude + $dlongitude
			],
			'latitude' => [
				'start' => $latitude - $dlatitude,
				'end' => $latitude + $dlatitude
			],
		];
	}

	/**
	 * 判断是否在有效范围内
	 *
	 * Date: 06/05/2018
	 * @author George
	 * @param float $sta_lon
	 * @param float $sta_lat
	 * @param float $des_lon
	 * @param float $des_lat
	 * @param int $radius
	 * @return bool
	 */
	public static function confine(float $sta_lon, float $sta_lat, float $des_lon, float $des_lat, int $radius)
	{
		$distance = self::distance($sta_lon, $sta_lat, $des_lon, $des_lat);
		return $distance - $radius < 0;
	}

	/**
	 * 计算两点间距离
	 *
	 * Date: 06/05/2018
	 * @author George
	 * @param float $sta_lon 起始点经度
	 * @param float $sta_lat 起始点纬度
	 * @param float $des_lon 目的地经度
	 * @param float $des_lat 目的地纬度
	 * @param string $unit 单位，默认是米
	 * @param int $decimal 计算精度
	 * @return float
	 */
	public static function distance(float $sta_lon, float $sta_lat, float $des_lon, float $des_lat, string $unit = 'm', int $decimal = 2)
	{
		$radius = 6370.996;

		$sta_lon = ($sta_lon * self::PI) / 180;
		$sta_lat = ($sta_lat * self::PI) / 180;
		$des_lon = ($des_lon * self::PI) / 180;
		$des_lat = ($des_lat * self::PI) / 180;

		$a = $sta_lat - $des_lat;
		$b = $sta_lon - $des_lon;

		$distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($sta_lat) * cos($des_lat) * pow(sin($b / 2), 2)));
		$distance = $distance * $radius * 1000;

		if ($unit === 'km') {
			$distance = $distance / 1000;
		}

		return round($distance, $decimal);
	}
}
